package com.ccc.upload.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.ccc.upload.controller.entity.UploadParam;
import com.ccc.upload.controller.entity.UploadResult;

import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;

@RestController
@CrossOrigin
@Slf4j
public class FileUploadController {

	@RequestMapping("uploadfile")
	public UploadResult uploadfile(MultipartFile file, UploadParam params) {

		String task = params.getIdentifier(); // 获取文件唯一标识符
		int chunk = params.getChunkNumber(); // 获取该分片在所有分片中的序号
		String filename = String.format("%s%d", task, chunk); // 构成该分片唯一标识符

		try {
			file.transferTo(new File(String.format("d:/test-upload/%s", filename)));
		} catch (IllegalStateException | IOException e) {
			log.error("%s", e);
		}

		return UploadResult.builder().filename(filename).build();
	}

	@RequestMapping("mergefile")
	public UploadResult mergefile(String identifier/* 文件的唯一标识符 */, String filename/* 上传文件的文件名 */,
			int totalChunks/* 总分片数 */) {

		String basePath = "d:/test-upload/";

		// 组装所有文件的路径
		String[] paths = new String[totalChunks];// 存放所有路径
		for (int chunk = 1 /* 分片开始序号 */; chunk <= totalChunks; chunk++) {
			paths[chunk - 1] = basePath + identifier + chunk;
		}

		mergeFiles(paths, basePath + filename);

		return UploadResult.builder().code(200).build();
	}

	/**
	 * TODO 利用nio FileChannel合并多个文件
	 * 
	 * @param fpaths
	 * @param resultPath
	 * @return
	 */
	public static boolean mergeFiles(String[] fpaths, String resultPath) {
		if (fpaths == null || fpaths.length < 1 || StringUtils.isBlank(resultPath)) {
			return false;
		}
		if (fpaths.length == 1) {
			return new File(fpaths[0]).renameTo(new File(resultPath));
		}

		File[] files = new File[fpaths.length];
		for (int i = 0; i < fpaths.length; i++) {
			files[i] = new File(fpaths[i]);
			if (StringUtils.isBlank(fpaths[i]) || !files[i].exists() || !files[i].isFile()) {
				return false;
			}
		}

		File resultFile = new File(resultPath);

		try {
			@Cleanup
			FileOutputStream fout = new FileOutputStream(resultFile, true);
			@Cleanup
			FileChannel resultFileChannel = fout.getChannel();
			for (int i = 0; i < fpaths.length; i++) {
				@Cleanup
				FileInputStream fin = new FileInputStream(files[i]);
				@Cleanup
				FileChannel blk = fin.getChannel();
				resultFileChannel.transferFrom(blk, resultFileChannel.size(), blk.size());
			}
		} catch (FileNotFoundException e) {
			log.error("%s", e);
			return false;
		} catch (IOException e) {
			log.error("%s", e);
			return false;
		}

		for (int i = 0; i < fpaths.length; i++) {
			files[i].delete();
		}

		return true;
	}

}
